package ws.jdbc.concurrent.driver.sqlserver;

import java.sql.*;
import ws.jdbc.concurrent.driver.sqlserver.tds.TDSMessage;
import static ws.jdbc.concurrent.driver.sqlserver.tds.rpc.StoredProcedures.*;

/**
 * Forward-only and read-only result set.
 * 
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
public class CResultSetForwardOnlyReadOnly extends CResultSet {

  protected Next nextImpl;

  protected CResultSetForwardOnlyReadOnly(TDSMessage message, Statement stmt) throws SQLException {
    super(message, stmt);
  }

  protected CResultSetForwardOnlyReadOnly(final TDSMessage message, final Statement stmt, final String sql) throws SQLException {
    this(message, stmt);

    if (fetchSize == 0) {
      tdsResultSet = message.executeSQLBatch(sql);
      setupBatchResultSet();
    } else {
      tdsResultSet = message.cursorOpen(sql, SP_CURSOROPEN_SCROLLOPT_FORWARD_ONLY, SP_CURSOROPEN_CCOPT_READ_ONLY);
      setupCursorResultSet();
    }
  }

  protected interface Next {

    boolean execute() throws SQLException;
  }

  protected final void setupBatchResultSet() {
    lastRow.set(tdsResultSet.rowCount());
    cacheBegining = 1;
    cacheEnd = cacheBegining + lastRow.get();

    nextImpl = new Next() {

      public boolean execute() throws SQLException {
        ++currentRow;
        if (currentRow < 1 || currentRow > lastRow.get()) {
          currentRow = ROW_BEFORE;
          rsIndex = -1;
          return false;
        } else {
          ++rsIndex;
          return true;
        }
      }
    };
  }

  protected final void setupCursorResultSet() {
    nextImpl = new Next() {

      public boolean execute() throws SQLException {
        ++currentRow;
        if (tdsResultSet.isEmpty() || !inCache()) {
          tdsResultSet = message.cursorFetch(tdsResultSet.getCursor(), SP_CURSORFETCH_FETCHTYPE_NEXT, currentRow, fetchSize);
          rsIndex = 0;
          forwardCache();
        } else {
          ++rsIndex;
        }
        if (tdsResultSet.isEmpty()) {
          currentRow = ROW_BEFORE;
          return false;
        } else {
          return true;
        }
      }
    };
  }

  @Override
  public boolean next() throws SQLException {
    return nextImpl.execute();
  }

  @Override
  public void setFetchDirection(int direction) throws SQLException {
    throw new SQLWarning("Fetch direction will be ignored, because the result set is 'forward-only'");
  }

  // <editor-fold defaultstate="collapsed" desc="Operations not supported by forward-only result set.">
  @Override
  public boolean previous() throws SQLException {
    throw new SQLException(Messages.msg_forward_only);
  }

  @Override
  public boolean absolute(int row) throws SQLException {
    throw new SQLException(Messages.msg_forward_only);
  }

  @Override
  public boolean relative(int rows) throws SQLException {
    throw new SQLException(Messages.msg_forward_only);
  }

  @Override
  public void afterLast() throws SQLException {
    throw new SQLException(Messages.msg_forward_only);
  }

  @Override
  public void beforeFirst() throws SQLException {
    throw new SQLException(Messages.msg_forward_only);
  }

  @Override
  public boolean first() throws SQLException {
    throw new SQLException(Messages.msg_forward_only);
  }

  @Override
  public boolean last() throws SQLException {
    throw new SQLException(Messages.msg_forward_only);
  }

  @Override
  public boolean isAfterLast() throws SQLException {
    throw new SQLFeatureNotSupportedException(Messages.msg_forward_only);
  }

  @Override
  public boolean isBeforeFirst() throws SQLException {
    throw new SQLFeatureNotSupportedException(Messages.msg_forward_only);
  }

  @Override
  public boolean isFirst() throws SQLException {
    throw new SQLFeatureNotSupportedException(Messages.msg_forward_only);
  }

  @Override
  public boolean isLast() throws SQLException {
    throw new SQLFeatureNotSupportedException(Messages.msg_forward_only);
  }
  // </editor-fold>

  // <editor-fold defaultstate="collapsed" desc="Operations not supported by read-only result set.">
  @Override
  public void cancelRowUpdates() throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void moveToCurrentRow() throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void moveToInsertRow() throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void updateDate(int columnIndex, Date x) throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void updateDouble(int columnIndex, double x) throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void updateInt(int columnIndex, int x) throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void updateString(int columnIndex, String x) throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void insertRow() throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void updateRow() throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public void deleteRow() throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }

  @Override
  public boolean rowDeleted() throws SQLException {
    throw new SQLException(Messages.msg_read_only);
  }
  // </editor-fold>
}
